﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Runtime.Serialization;
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections;
using System.Reflection;
using BrainTechLLC.ThreadSafeObjects;
using BrainTechLLC;
#if USE_HYPER
using Hyper.ComponentModel;
#endif

namespace BrainTechLLC.ThreadSafeObjects
{
    /// <summary>
    /// Thread-safe lookup, creating/populating values if not found in the lookup
    /// </summary>
    /// <typeparam name="T1"></typeparam>
    /// <typeparam name="T2"></typeparam>
#if NO_SILVERLIGHT
    [TypeDescriptionProvider(typeof(HyperTypeDescriptionProvider))]
#endif
    [Serializable]
    [DataContract]
    public class ThreadSafeLookupOnDemand<T1, T2> : ThreadSafeLookup<T1, T2> where T2 : class, new()
    {
        protected Cached<List<T2>> _cachedList;

        public Cached<List<T2>> CachedList
        {
            get
            {
                return Populate.OnDemand<Cached<List<T2>>>(ref _cachedList, () => new Cached<List<T2>>(
                     delegate(object param, out List<T2> result, object[] args) { result = base.AllItems; return true; }));
            }
        }

        public void MarkDirty()
        {
            if (_cachedList != null)
                _cachedList.MarkDirty();
        }

        public new List<T2> AllItems { get { return CachedList.GetItem(); } }

        public bool Contains(T1 key)
        {
            return ContainsKey(key);
        }

        /// <summary>
        /// Gets an item, or if not found in the collection, creates a new item and adds it to the collection
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public T2 Get(T1 key)
        {
            T2 item = this[key];

            if (item == null)
            {
                item = new T2();
                AddOrSet(key, item);
            }

            return item;
        }                

        public new void AddOrSet(T1 key, T2 item)
        {
            base.AddOrSet(key, item);
            MarkDirty();
        }

        /// <summary>
        /// Gets an item, or if not found in the collection, creates a new item and adds it to the collection
        /// </summary>
        /// <param name="key"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public T2 Get(T1 key, Func<T1, T2> func)
        {
            T2 item = this[key];

            if (item == null)
            {
                item = func(key);
                base.AddOrSet(key, item);

                if (_cachedList != null)
                    _cachedList.MarkDirty();
            }

            return item;
        }
    }
}

